//
// Created by Symps on 2025/9/15.
//

#ifndef ARRAYLIST_H
#define ARRAYLIST_H

#include <iostream>
#include <stdexcept>
using std::cout;
using std::endl;

template <typename T>
class ArrayList {
    friend std::ostream& operator<<(std::ostream& out, const ArrayList<T>& list) {
        out << "[";
        for (int i = 0; i < list._size; i++) {
            out << list._data[i];
            if (i != list._size - 1) {
                out << ", ";
            }
        }
        out << "]";
        return out;
    }

public:
    explicit ArrayList(const int capacity = 8) : _capacity(capacity), _size(0), _data(new T[capacity]) {
        if (capacity <= 0) {
            throw std::runtime_error("Capacity must be greater than 0");
        }
    }

    ArrayList(const ArrayList& list) : _capacity(list._capacity), _size(list._size), _data(new T[list._capacity]) {
        for (int i = 0; i < _size; i++) {
            _data[i] = list._data[i];
        }
        _capacity = list._capacity;
        _size = list._size;
    }

    ~ArrayList() {
        delete[] _data;
        _size = 0;
    }

    [[nodiscard]] int size() const {
        return _size;
    }

    [[nodiscard]] int capacity() const {
        return _capacity;
    }

    void addHead(const T& value) {
        ensureCapacity();

        for (int i = _size; i > 0; i--) {
            _data[i] = _data[i - 1];
        }
        _data[0] = value;
        _size++;
    }

    void add(const T& value) {
        ensureCapacity();
        _data[_size++] = value;
    }

    void insert(const T& value, const int index) {
        if (index > _size || index < 0) {
            throw std::runtime_error("Index out of range");
        }
        if (index == _size) {
            add(value);
            return;
        }
        ensureCapacity();
        for (int i = _size; i > index; i--) {
            _data[i] = _data[i - 1];
        }
        _data[index] = value;
        _size++;
    }

    void removeHead() {
        remove();
        for (int i = 0; i < _size; i++) {
            _data[i] = _data[i + 1];
        }
    }

    void remove() {
        if (_size == 0) {
            throw std::runtime_error("ArrayList is empty");
        }
        _size--;
    }

    void remove(const int index) {
        if (index > _size - 1 || index < 0) {
            throw std::runtime_error("Index out of range");
        }
        _size--;
        for (int i = index; i < _size; i++) {
            _data[i] = _data[i + 1];
        }
    }

    int find(const T& value) {
        for (int i = 0; i < _size; i++) {
            if (_data[i] == value) {
                return i;
            }
        }
        return -1;
    }

    ArrayList& operator=(const ArrayList& list) {
        if (this == &list) {
            return *this;
        }
        _capacity = list._capacity;
        _size = list._size;
        delete[] _data;
        _data = new T[_capacity];
        for (int i = 0; i < _size; i++) {
            _data[i] = list._data[i];
        }
        return *this;
    }

private:
    int _capacity;
    int _size;
    T* _data;

    void ensureCapacity() {
        if (_size == _capacity) {
            _capacity = (_capacity == 0 ? 1 : _capacity * 2);
            T* newData = new T[_capacity];
            if (_data != nullptr && _size > 0) {
                move(_data, _data + _size, newData);
                delete[] _data;
            }
            _data = newData;
        }
    }
};

#endif //ARRAYLIST_H
